package rpc

import (
	"fmt"

	"github.com/AsynkronIT/protoactor-go/actor"

	nproto "nggs/network/protocol"
)

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
type MessageDispatcher struct {
	dispatchers map[MessageID]MessageHandler
	protocol    IProtocol
}

func NewMessageDispatcher() *MessageDispatcher {
	return &MessageDispatcher{
		dispatchers: map[MessageID]MessageHandler{},
	}
}

func (m *MessageDispatcher) Register(id MessageID, handler MessageHandler) (err error) {
	if _, ok := m.dispatchers[id]; ok {
		err = fmt.Errorf("rpc message handler already register, id=%d", id)
		return
	}

	m.dispatchers[id] = handler

	return
}

func (m *MessageDispatcher) Dispatch(iProtocol IProtocol, sender *actor.PID, iRecv IMessage, ctx actor.Context, args ...interface{}) (iSend IMessage, err error) {
	handler, ok := m.dispatchers[iRecv.MessageID()]
	if !ok {
		err = &nproto.ErrNoDispatcher{MessageID: iRecv.MessageID()}
		return
	}

	if iRecv.ResponseMessageID() > 0 {
		iSend, err = iProtocol.Produce(iRecv.ResponseMessageID())
		if err != nil {
			err = fmt.Errorf("produce rpc response message fail, id=%d, %w", iRecv.ResponseMessageID(), err)
			return
		}
	}

	handler(sender, iRecv, iSend, ctx, args...)

	return
}
